// 数组类型的重新构造

type tuple = [1, 2, 3]

type Push<Arr extends unknown[], Ele> = [...Arr, Ele]
type Test1 = Push<tuple, 5>

type tuple1 = [1, 2]
type tuple2 = ['a', 'b']

type Zip<One extends [unknown, unknown], Other extends [unknown, unknown]> = One extends [infer OneFirst, infer OneSecond] ?
        Other extends [infer OtherFirst, infer OtherSecond] ? [[OneFirst, OtherFirst], [OneSecond, OtherSecond]] : [] : []

type Test2 = Zip<tuple1, tuple2>


type ZipDigui<One extends unknown[], Other extends unknown[]> = One extends [infer OneFirst, ...infer OneRest] ?
        Other extends [infer OtherFirst, ...infer OtherRest] ? [[OneFirst, OtherFirst], ...ZipDigui<OneRest, OtherRest>] : [] : []

type tuple3 = [1, 2, 3, 4]
type tuple4 = ['a', 'b', 'd', 'e']
type Test3 = ZipDigui<tuple3, tuple4>

// 字符串类型的重新构造

type CapitalizeStr<Str extends string> = Str extends `${infer First}${infer Rest}` ? `${Uppercase<First>}${Rest}` : Str

type Test4 = CapitalizeStr<'abin'>

type CamelCase<Str extends string> = Str extends `${infer Left}_${infer Right}${infer Rest}` ? `${Left}${Uppercase<Right>}${CamelCase<Rest>}` : Str

type Test5 = CamelCase<'nest_learn_go'>

type DropSubStr<Str extends string, SubStr extends string> = Str extends `${infer Prefix}${SubStr}${infer Suffix}` ? DropSubStr<`${Prefix}${Suffix}`, SubStr> : Str

type Test6 = DropSubStr<'abababacc', 'ab'>

// 函数类型的重新构造

type AppendArgument<Func extends Function, Arg> = Func extends (...args: infer args) => infer ReturnType ? (...args: [...args, Arg]) => ReturnType : never

type Test7 = AppendArgument<(name: string, age: number) => [], boolean>

// 索引类型的重新构造

type Mapping<Obj extends object> = {
        [Key in keyof Obj]: [Obj[Key], Obj[Key], Obj[Key]]
}
interface obj1 {
        name: string,
        age: number
}
type Test8 = Mapping<obj1>

type UppercaseKey<Obj extends Record<string, any>> = {
        [Key in keyof Obj as Uppercase<Key & string>]: Obj[Key]
}

type Test9 = UppercaseKey<obj1>

type ToReadonly<T> = {
        readonly [Key in keyof T] : T[Key]
}

type Test10 = ToReadonly<obj1>
 
type ToPartial<T> = {
        [Key in keyof T]?: T[Key]
}

type Test11 = ToPartial<obj1>

type ToMutable<T> = {
        -readonly [Key in keyof T]: T[Key]
}

type Test12 = ToMutable<ToReadonly<obj1>>

type FilterByValueType<Obj extends Record<string, any>, ValueType> =  {
        [Key in keyof Obj as Obj[Key] extends ValueType ? Key : never] : Obj[Key]
}

interface Person {
        name: string,
        age: number,
        hobby: string[]
}
type Test13 = FilterByValueType<Person, string | number>